using System;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.WindowsAzure.StorageClient;

namespace Microsoft.WindowsAzure.Accelerator
{
    /// <summary>
    /// Extensions to the CloudBlobContainer class, which represents a container in the Windows Azure Blob service.
    /// </summary>
    public static class CloudBlobContainerExtensions
    {
        private readonly static Regex _isContainerName = new Regex(@"^(([a-z]|\d){1}([a-z]|-|\d){1,61}([a-z]|\d){1}){1}|(\$root){1}$", RegexOptions.Compiled);
       
        /// <summary>
        /// Test for the existence of a blob container.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <returns></returns>
        public static Boolean Exists(this CloudBlobContainer container)
        {
            try
            {
                container.FetchAttributes();
                return true;
            }
            catch (StorageClientException e)
            {
                if (e.ErrorCode == StorageErrorCode.ResourceNotFound || e.ErrorCode == StorageErrorCode.ContainerNotFound || e.ErrorCode == StorageErrorCode.BlobNotFound)
                    return false;
                throw;
            }
        }

        /// <summary>
        /// Determines whether the name is a valid container name.
        /// </summary>
        /// <param name="name">The name.</param>
        public static Boolean IsValidContainerName(String name)
        {
            return String.IsNullOrEmpty(name) ? false : _isContainerName.IsMatch(name);
        }

        /// <summary>
        /// Creates the container.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="access">The access permissions.</param>
        public static void CreateContainer(this CloudBlobContainer container, BlobContainerPublicAccessType access)
        {
            for (Int32 i = 1; i <= 10; i++)
            {
                try 
                {
                    container.CreateIfNotExist();
                    using (var ms = new MemoryStream())
                    {
                        ms.Seek(0, SeekOrigin.Begin);
                        container.GetBlobReference("__testblob").UploadFromStream(ms);
                        container.GetBlobReference("__testblob").Delete();
                    }
                    BlobContainerPermissions permissions = container.GetPermissions();
                    permissions.PublicAccess = access;
                    container.SetPermissions(permissions);
                    break;
                }
                catch (StorageClientException e)
                {
                    if (e.ErrorCode == StorageErrorCode.ContainerAlreadyExists || e.ErrorCode == StorageErrorCode.ResourceAlreadyExists)
                    {
                        return;
                    }
                    Trace.TraceError(e.Message);
                    Trace.TraceInformation("Unable to create cloud container, retrying in 30 seconds...");
                    Thread.Sleep(30000);
                    if (i == 3)
                    {
                        throw;
                    }
                }
            }
        }
    }
}